package net.minecraft.src;

import java.util.*;

public class BlockFlipFlop extends  Block
{
	
	static int []  directions = new  int[]{1,2,3,0}; 
	
	static  final int directionMask =  3; 
	static  final int stateMask =  12; 
	
	static  final int  readyToRunNoPower = 0;
	static  final int  readyToRunPower = 4;
	static  final int  disabledPower = 8;
	static  final int  disabledNoPower = 12;	
	static  Map<Coords,Integer>  coordsState = new  HashMap<Coords,Integer>();	
	static Map< Integer, Integer  > globalToLocal = new HashMap< Integer,Integer >(){
	    {
	        put(2, 0);
	        put(5, 1);
	        put(3, 2);
	        put(4, 3);
	    }
	};
	

	static Map< Integer, Integer  > localToGlobal = new HashMap< Integer,Integer >(){
	    {
	        put(0,2);
	        put(1,5);
	        put(2,3);
	        put(3,4);
	    }
	};
	
	
	
	static Map< Integer, Integer  > orientationToIndex = new HashMap< Integer,Integer >(){
	    {
	        put(directions[0], 0);
	        put(directions[1], 1);
	        put(directions[2], 2);
	        put(directions[3], 3);
	    }
	};
	static Map< Object,int []  > providingPowerModificators = new HashMap< Object,int [] >(){
		{
        	put( new Integer(globalToLocal.get(5)), new int[] {1,0,0} );
        	put( new Integer(globalToLocal.get(4)), new int[] {-1,0,0} );
        	put( new Integer(globalToLocal.get(2)), new int[] {0,0,-1} );
        	put( new Integer(globalToLocal.get(3)), new int[] {0,0,1} );
		}
		
	};
	
	 
	static final int outputShift  =  2;
	static final int inputClkShift  =  1;
	
    public int getRenderBlockPass()
    {
        return 0;
    }
    protected BlockFlipFlop(int i)
    {
        super(i, Material.circuits);

        	
    }    
    public  void setPositionMetadata(World world, int i, int j, int k, int  positionValue)
    {
    	int  saveBlockId = world.getBlockMetadata(i, j, k) & 8;
    	
    	world.setBlockMetadataWithNotify(i, j, k, positionValue + saveBlockId);
    }
    
    public  int getPositionMetadata(World world, int i, int j, int k)
    {
    	return world.getBlockMetadata(i, j, k) & directionMask;

    }
    
    public  int getPositionMetadata(int  meta)
    {
    	return meta & directionMask;

    }
    
    public  void setPowerStateMetadata(World world, int i, int j, int k, int powerState)
    {
    	int  savePositionId = world.getBlockMetadata(i, j, k) & directionMask;
    	
    	world.setBlockMetadataWithNotify(i, j, k, savePositionId + powerState);
    }
    

    public  boolean getInternalPowerState(int meta)
    {
    	
    	if(
    			(meta & stateMask) == readyToRunPower
    		 || (meta & stateMask) == disabledPower
    	   )
    		return  true;
    	else
			return  false;    	
    	
    	
    }
    
    public  boolean getInternalPowerState(World world, int i, int j, int k)
    {
    	 return getInternalPowerState( getPowerStateMetadata(world, i, j, k) );  	
    	
    	
    }
    public  void setInternalPowerState(World world, int i, int j, int k, boolean  powerState)
    {
    	
    	if(powerState)
    		setPowerStateMetadata(world, i, j, k, 8);
    	else
    		setPowerStateMetadata(world, i, j, k, 0);

    }
    public  int getPowerStateMetadata(World world, int i, int j, int k)
    {
    	return world.getBlockMetadata(i, j, k) & stateMask;
    	
    }
    
    public int getBlockTextureFromSideAndMetadata(int i, int j)
    {

    	if(
    			!globalToLocal.containsKey(i)	
    	  )
            return mod_FlipFlop.flipFlopMain;	
    	
    	
    	i = globalToLocal.get(i);
    	
    	
        if( i ==  getPositionMetadata(j) ) 
        {
            return mod_FlipFlop.flipFlopIn;
        }
        else if( i ==  getOutputDirection( getPositionMetadata(j) ) )
        {
        	
        	return
        			getInternalPowerState(j)
        		  ? mod_FlipFlop.flipFlopOutActive
        		  : mod_FlipFlop.flipFlopOut;		
        }
        else if( i ==   getClkDirection( getPositionMetadata(j) ) )
        {
        	return mod_FlipFlop.flipFlopClk;
        }
        else
        {
            return mod_FlipFlop.flipFlopMain;
        }
    }
    public void onBlockPlacedBy(World world, int i, int j, int k, EntityLiving entityliving)
    {
        int l = MathHelper.floor_double((double)((entityliving.rotationYaw * 4F) / 360F) + 0.5D) & 3;

        setPositionMetadata(world, i, j, k, l);
 
    }


    public void onBlockAdded(World world, int i, int j, int k)
    {
			super.onBlockAdded(world, i, j, k);	
    }

    public void onBlockRemoval(World world, int i, int j, int k)
    {
    		super.onBlockRemoval(world, i, j, k);

    }

    private  boolean isClkPowerd(World world, int i, int j, int k)
    {
    	int meta = getClkDirection( getPositionMetadata( world, i, j, k) );

    	
    	return world.isBlockIndirectlyProvidingPowerTo(
    			i + providingPowerModificators.get(meta)[0]
    		  , j + providingPowerModificators.get(meta)[1]
    		  , k + providingPowerModificators.get(meta)[2]
    		  ,localToGlobal.get(meta) );
    	
    }
    
    private  boolean isInputPowerd(World world, int i, int j, int k)
    {

        int meta = getPositionMetadata(world,i, j, k);
        return  world.isBlockIndirectlyProvidingPowerTo(
    			i + providingPowerModificators.get(meta)[0]
    		  , j + providingPowerModificators.get(meta)[1]
    		  , k + providingPowerModificators.get(meta)[2]
    		  , localToGlobal.get(meta) );
    }
    
    private int getOutputDirection( int metadata )
    {
    	if (!orientationToIndex.containsKey(metadata))
    		return  metadata;
		return	directions[ ( orientationToIndex.get( metadata ) + outputShift ) % 4 ];
    }
  
    private int getClkDirection( int metadata )
    {
    	if (!orientationToIndex.containsKey(metadata))
    		return  metadata;
		return	directions[ ( orientationToIndex.get( metadata ) + inputClkShift ) % 4 ];
    }
    
    public boolean isPoweringTo(IBlockAccess iblockaccess, int i, int j, int k, int l)
    {
    	int  meta = iblockaccess.getBlockMetadata(i, j, k);
    	
    	if (!globalToLocal.containsKey(l))
    		return false;
    	
		if ( globalToLocal.get(l)  ==  getPositionMetadata(meta) )
			return  getInternalPowerState(meta);
    	
    	return  false;

    }

    
    public boolean renderAsNormalBlock()
    {
        return false;
    }
    
    public void onNeighborBlockChange(World world, int i, int j, int k, int l)
    {	
    	Coords  coords = new Coords(i,j,k);
    	if( coordsState.containsKey(coords ))
    		return;
    	int  blockState = getPowerStateMetadata( world, i, j, k);

    	if( 
    			   disabledPower  == blockState
    			|| disabledNoPower  == blockState
    	  )
    	{
    		 if ( !isClkPowerd(world, i, j, k) )
    		{
    			 if( disabledPower  == blockState )
    				 coordsState.put(coords, readyToRunPower);
    			 else
    				 coordsState.put(coords, readyToRunNoPower);

    			 
    		}
 		
    	}
    	else
    	{
    		if ( isClkPowerd(world, i, j, k) )
    		{
    			if( isInputPowerd(world, i, j, k) )
    				coordsState.put(coords,disabledPower);
		    	else
		    		coordsState.put(coords, disabledNoPower);
    			
    			
    		}
    	}
    	
    	world.scheduleBlockUpdate(i, j, k, blockID,tickRate());

    }
    public void updateTick(World world, int i, int j, int k, Random random)
    {	
    	Coords  coords = new Coords(i,j,k);
    	if( coordsState.containsKey(coords ))
    	{
	    	int  newState = coordsState.get(coords);
	    	coordsState.remove(coords);
	    	setPowerStateMetadata(world, i, j, k, newState);
    	}

    }
    public int tickRate()
    {
        return 5;
    }
    
    
}